Grundfälle der ebenen Vektoralgebra
Oktober 2020
Keywords: Webkinematik, Webentwicklung, Getriebekinematik, Mechanismentechnik, Bewegungsübertragung, Kraftübertragung, Vektoralgebra, g2, mec2
6.3 Grundfall IV
6.3.1 Aufgabenstellung
Prüfen Sie den vorliegenden Mechanismus auf Freiheitsgrad, Anzahl seiner Maschen und Umlauffähigkeit. Analysieren Sie den Mechanismus anschließend und stellen Sie ihn mit g2 interaktiv im Browser so dar, dass er nur in montierbaren Positionen gerendert wird.
Geg.:
6.3.2 Freiheitsgrad und Maschenzahl
Der Freiheitsgrad nach Grübler lässt sich über folgende Gleichung bestimmen:
mit
Anzahl der Gelenke denen 1 Freiheitsgrad entzogen wurde Anzahl der Gelenke denen 2 Freiheitsgrade entzogen wurden Anzahl der Glieder Die Maschenanzahl berechnet sich durch
Für den gegebenen Mechanismus gilt
6.3.3 Umlauffähigkeit:
Die Umlauffähigkeit eines Viergelenks ist definiert durch
beziehungsweise
für durchschlagende Getriebe. Montierbarkeit ist gegeben wenn
Für das vorliegende Getriebe gilt
Es ist also nicht umlauffähig aber grundsätzlich montierbar, denn
6.3.4 Analyse:
Aus der Maschengleichung lässt sich Grundfall IV identifizieren
mit
Grundfall IV:
Lösung:
mit
Mit getauschten Variablen ergibt sich für unseren Mechanismus
mit
Quadrieren der Hilfsgeraden
Es folgen die unbekannten Winkel
Der Mechanismus ist damit vollständig bestimmt.
6.3.5 Code
Wir erstellen nach bekannten Schema eine neue HTML-Datei (bzw. ändern schlauerweise eine fertige wie z.B. die Kurbel mit 2 Slidern). Wir benötigen unter anderem ein 600x400px Canvas sowie einen Range-Input sowie Output für
Wir erstellen ein mec-Objekt mit Properties für die Gliedlängen
Das mec-Objekt sieht dann so aus:
mec = {
a:120,
b:200,
c:150,
d:250,
get ephi() { return { x:Math.cos(phi), y:Math.sin(phi) }; },
get g() { return {x:this.d - this.a*Math.cos(phi), y:- this.a*Math.sin(phi)}; },
get gg() { return this.a*this.a + this.d*this.d - 2*this.a*this.d*Math.cos(phi); },
get theta() {
var gg = this.gg, bb_gg = (this.b*this.b)/gg, g = this.g,
lambda = 0.5*(bb_gg - this.c*this.c/gg + 1),
mue = Math.sqrt(bb_gg - lambda*lambda);
return Math.atan2( (1/this.b)*(lambda*g.y + mue*g.x), (1/this.b)*(lambda*g.x - mue*g.y) )
},
get etheta() { return { x:Math.cos(this.theta), y:Math.sin(this.theta)}; },
get psi() {
var etheta = this.etheta;
return Math.atan2( (1/this.c)*(this.b*etheta.y - this.g.y), (1/this.c)*(this.b*etheta.x - this.g.x) )
},
get epsi() { return { x:Math.cos(this.psi), y:Math.sin(this.psi)}; },
// Gelenkpunkte
A0: {x:0, y:0},
get B0() { return {x:this.d, y:0} },
get A() { return {x:this.A0.x + this.a*this.ephi.x, y:this.A0.y + this.a*this.ephi.y}; },
get B() { return {x:this.B0.x + this.c*this.epsi.x, y:this.B0.y + this.c*this.epsi.y}; }
}
Nachdem wir world-Objekt
// baut und initialisiert statische Umgebung
world = g2().clr()
.view({cartesian:true,x:150,y:150}) // Nullpunkt verschoben
.use({grp:g})
.nodfix({x:0,y:0})
.nodfix(mec.B0),
und position()-Funktion
function position() {
g.del()
.beam2({pts:[mec.A0.x, mec.A0.y, mec.A.x, mec.A.y, mec.B.x, mec.B.y, mec.B0.x, mec.B0.y ]})
.nod(mec.A)
.nod(mec.B)
}
angepasst haben, können wir den Mechanismus im Browser betrachten und stellen fest, dass er in Stellungen gerendert werden kann, die mit der gegebenen Geometrie unmöglich erreicht werden können. Wir müssen also, falls wir den für Math.sqrt(mec.gg) < (mec.a + mec.b).
Diese Bedingung prüfen wir in der Funktion setPhi(), in welcher wir nur dirty auf true setzen und dem Output das Slider-Value zuweisen, wenn das eben genannte zutrifft. Fall die Bedingung false liefert, ändern wir dirty nicht und weisen dem Output einen String zu, der anzeigt, dass der eingestellte Wert für setPhi() zusätzlich das Attribut hidden des Span-Elements auf true oder false setzen, je nachdem ob das Grad Zeichen sichtbar sein soll oder nicht. Zusätzlich können wir mittels *ID*.style["color"] = "*FARBE*" noch ein bisschen Styling für den Output betreiben.
Wir erhalten also folgenden Output
<output id="phiout" for="phislider">0</output><span id="grad">°</span>
und ändern setPhi() zu
function setPhi() {
if (phislider.value != phiout.value) {
phi = phislider.value*pi/180;
if (Math.sqrt(mec.gg) < (mec.b + mec.c)) {
phiout.innerHTML = phislider.value;
phiout.style["color"] = "black";
grad.hidden = false;
dirty = true;
} else {
phiout.style["color"] = "red";
phiout.innerHTML = "unzulaessiger Bereich";
grad.hidden = true;
}
}
}
6.3.6 Ergebnis
Der fertige Quelltext sollte folgendermaßen aussehen:
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<title>Kurbelschwinge</title>
</head>
<body>
<h2>Kurbelschwinge - Grundfall 4</h2>
<canvas id="c" width="600" height="400" style="border-width:1px;border-style:solid"></canvas>
<br>
<label for="phislider">φ:
<input type="range" id="phislider" style="width:550px;vertical-align:middle;padding:0" min="0" max="360" value="0">
<output id="phiout" for="phislider">0</output><span id="grad">°</span>
</label>
<script src="https://gitcdn.xyz/repo/goessner/g2/master/src/g2.js"></script>
<script>
const cnv = document.getElementById('c'),
ctx = cnv.getContext('2d'),
phislider = document.getElementById('phislider'),
phiout = document.getElementById('phiout')
grad = document.getElementById('grad'),
pi = Math.PI,
phi = 0, // Laufvariable
mec = {
a:120,
b:200,
c:150,
d:250,
get ephi() { return { x:Math.cos(phi), y:Math.sin(phi) }; },
get g() { return {x:this.d - this.a*Math.cos(phi), y:- this.a*Math.sin(phi)}; },
get gg() { return this.a*this.a + this.d*this.d - 2*this.a*this.d*Math.cos(phi); },
get theta() {
var gg = this.gg, bb_gg = (this.b*this.b)/gg, g = this.g,
lambda = 0.5*(bb_gg - this.c*this.c/gg + 1),
mue = Math.sqrt(bb_gg - lambda*lambda);
return Math.atan2( (1/this.b)*(lambda*g.y + mue*g.x), (1/this.b)*(lambda*g.x - mue*g.y) )
},
get etheta() { return { x:Math.cos(this.theta), y:Math.sin(this.theta)}; },
get psi() {
var etheta = this.etheta;
return Math.atan2( (1/this.c)*(this.b*etheta.y - this.g.y), (1/this.c)*(this.b*etheta.x - this.g.x) )
},
get epsi() { return { x:Math.cos(this.psi), y:Math.sin(this.psi)}; },
// Gelenkpunkte
A0: {x:0, y:0},
get B0() { return {x:this.d, y:0} },
get A() { return {x:this.A0.x + this.a*this.ephi.x, y:this.A0.y + this.a*this.ephi.y}; },
get B() { return {x:this.B0.x + this.c*this.epsi.x, y:this.B0.y + this.c*this.epsi.y}; }
},
g = g2(),
// baut und initialisiert statische Umgebung
world = g2().clr()
.view({cartesian:true,x:150, y:150}) // Nullpunkt verschoben
.use({grp:g})
.nodfix({x:0,y:0})
.nodfix(mec.B0);
let dirty = true; // wenn true gibt es was zu aktualisieren
function position() {
g.del()
.beam2({pts:[mec.A0.x, mec.A0.y, mec.A.x, mec.A.y, mec.B.x, mec.B.y, mec.B0.x, mec.B0.y ]})
.nod(mec.A)
.nod(mec.B)
}
function render() {
if (dirty) {
position(); // aktualisiere Position
world.exe(ctx); // rendert world in den Context
dirty = false;
}
requestAnimationFrame(render); // asynchroner callback von render(), keine Rekursion!
}
function setPhi() {
if (phislider.value != phiout.value) {
phi = phislider.value*pi/180;
if (Math.sqrt(mec.gg) < (mec.b + mec.c)) {
phiout.innerHTML = phislider.value;
phiout.style["color"] = "black";
grad.hidden = false;
dirty = true;
} else {
phiout.style["color"] = "red";
phiout.innerHTML = "unzulaessiger Bereich";
grad.hidden = true;
}
}
}
/*
* Initialisierung
*/
// Eventlistener hinzufuegen
phislider.addEventListener("input",setPhi);
// Animation starten
render();
</script>
</body>
</html>